package com.daigoudao.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.apache.commons.lang.StringUtils;

import com.daigoudao.config.ConfigManager;

/* *
 *类名：AlipayFunction
 *功能：支付宝接口公用函数类
 *详细：该类是请求、通知返回两个文件所调用的公用函数核心处理文件，不需要修改
 *版本：3.2
 *日期：2011-03-17
 *说明：
 *以下代码只是为了方便商户测试而提供的样例代码，商户可以根据自己网站的需要，按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用，只是提供一个参考。
 */

public class AlipayCore {

	/**
	 * 生成签名结果
	 * 
	 * @param sArray
	 *            要签名的数组
	 * @return 签名结果字符串
	 */
	public static String buildMysign(TreeMap<String, String> params) {
		TreeMap<String, String> newParams = paraFilter(params);
		String prestr = createLinkString(newParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		prestr = prestr + getAlipayConfig(Constants.KEY); // 把拼接后的字符串再与安全校验码直接连接起来
		String mysign = MD5Util.md5(prestr, Constants.UTF_ENCODING);
		return mysign;
	}

	/**
	 * 构造即时到账接口，增加基本配置
	 * 
	 * @param paramMap
	 */
	public static void create_direct_pay_by_user(
			TreeMap<String, String> paramMap) {
		paramMap.put(Constants.SERVICE, getAlipayConfig(Constants.SERVICE));
		paramMap.put(Constants.PARTNER, getAlipayConfig(Constants.PARTNER));
		paramMap.put(Constants.RETURN_URL,
				getAlipayConfig(Constants.RETURN_URL));
		paramMap.put(Constants.NOTIFY_URL,
				getAlipayConfig(Constants.NOTIFY_URL));
		paramMap.put(Constants.SELLER_ID, getAlipayConfig(Constants.SELLER_ID));
		paramMap.put(Constants.INPUT_CHARSET, Constants.UTF_ENCODING);
		paramMap.put(Constants.PAYMENT_TYPE, Constants.PAYMENT_TYPE_VALUE);
	}

	/**
	 * 除去数组中的空值和签名参数
	 * 
	 * @param sArray
	 *            签名参数组
	 * @return
	 */
	public static TreeMap<String, String> paraFilter(
			TreeMap<String, String> sArray) {
		Iterator<Entry<String, String>> iterator = sArray.entrySet().iterator();
		TreeMap<String, String> filterMap = new TreeMap<String, String>();
		while (iterator.hasNext()) {
			Entry<String, String> entry = iterator.next();
			if (entry.getValue() == null
					|| StringUtils.isBlank(entry.getValue())
					|| Constants.SIGN.equalsIgnoreCase(entry.getKey())
					|| Constants.SIGN_TYPE.equalsIgnoreCase(entry.getKey())) {
				continue;
			}
			filterMap.put(entry.getKey(), entry.getValue());
		}
		return filterMap;
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	public static String createLinkString(TreeMap<String, String> params) {

		StringBuilder link = new StringBuilder();
		for (Map.Entry<String, String> entry : params.entrySet()) {
			link.append(entry.getKey()).append("=").append(entry.getValue())
					.append("&");
		}
		link.deleteCharAt(link.length() - 1);

		return link.toString();
	}

	/**
	 * 验证消息是否是支付宝发出的合法消息
	 * 
	 * @param params
	 *            通知返回来的参数数组
	 * @return 验证结果
	 */
	public static boolean verify(TreeMap<String, String> params)
			throws IOException {
		String sign = buildMysign(params);
		if (sign.equals(params.get(Constants.SIGN))) {
			return (params.containsKey(Constants.NOTIFY_ID) && verifyResponse(params
					.get(Constants.NOTIFY_ID)));
		} else {
			return false;
		}
	}

	/**
	 * 获取远程服务器ATN结果,验证返回URL
	 * 
	 * @param notify_id
	 *            通知校验ID
	 * @return 服务器ATN结果 验证结果集： invalid命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空 true
	 *         返回正确信息 false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
	 */
	private static boolean verifyResponse(String notify_id) throws IOException {
		// 获取远程服务器ATN结果，验证是否是支付宝服务器发来的请求

		String partner = getAlipayConfig(Constants.PARTNER);
		String verify_url = Constants.HTTPS_VERIFY_URL + Constants.PARTNER
				+ "=" + partner + "&" + Constants.NOTIFY_ID + "=" + notify_id;
		return checkUrl(verify_url);
	}

	/**
	 * 获取远程服务器ATN结果
	 * 
	 * @param urlvalue
	 *            指定URL路径地址
	 * @return 服务器ATN结果 验证结果集： invalid命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空 true
	 *         返回正确信息 false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
	 */
	private static boolean checkUrl(String urlvalue) throws IOException {
		String inputLine = "";

		URL url = new URL(urlvalue);
		HttpURLConnection urlConnection = (HttpURLConnection) url
				.openConnection();
		if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
			BufferedReader in = new BufferedReader(new InputStreamReader(
					urlConnection.getInputStream()));
			inputLine = in.readLine().toString();
		}
		return inputLine.equalsIgnoreCase("true");
	}

	private static String getAlipayConfig(String configXPath) {
		return ConfigManager.getConfigString(Constants.ALIPAY_CONFIG
				+ configXPath);
	}
}
